package cn.keniykey.mc.landterritory.database;

import java.io.IOException;
import java.lang.reflect.Type;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.UUID;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import cn.keniykey.mc.landterritory.land.api.LandPosition;
import cn.keniykey.mc.landterritory.land.api.LandRange;
import cn.keniykey.mc.landterritory.toolkit.DebugUtil;

public abstract class AbDataBaseCore {
	private static final Gson gson = new Gson();
	private static final Type gson_parameter_type = new TypeToken<HashMap<String,HashSet<String>>>(){}.getType();
	private static final Type gson_flags_type = new TypeToken<HashSet<String>>(){}.getType();
	
	AbDataBaseCore() {}
	
	public abstract AbDataBase getDataBase();
	protected abstract void initDataBase() throws SQLException;
	
	public long initLand(UUID owner,String landname,int type,LandRange range,LandPosition pos,int level, int price,
			boolean overlap,boolean system) throws IOException, SQLException {
		//领地数据库land_data,rowid为领地ID,持有人owner[varchar],领地名name[nvarchar],领地类型type[int],领地范围range[blob],领地传送点pos[blob],领地标记flags[blob],标记参数parameter[blob]
		//领地等级level[int],领地出售价格price[int],领地覆盖许可overlap[boolean[int]],领地系统归属system[boolean[int]]
		final String insert_sql = "insert into `land_data` VALUES (?,?,?,?,?,?,?,?,?,?,?,?);";
		DebugUtil.info("数据库指令[initLand]：初始化领地数据，添加领地基础数据分配id，添加进领地数据数据库");
		this.getDataBase().excute(insert_sql, null,owner.toString(),landname,type,range.toJson(),pos.toJson(),null,null,level,price,overlap,system);
		final String select_sql = "select `id` from `land_data` where `name` = ? limit 1;";
		try(final ResultSet rs = this.getDataBase().query(select_sql, landname)) {
			if(rs.next()) return rs.getLong("id");
		}
		DebugUtil.info("数据库指令[initLand]：疑似将领地数据写进数据库失败，无法获取到 " + landname + " 数据列，无法获取领地id");
		final String delete_str = "delete from `land_data` where `name` = ?;";
		try {
			this.getDataBase().excute(delete_str, landname);
		}catch(Exception ex) {
			DebugUtil.info("数据库指令[initLand]异常：无法删除添加失败的领地数据");
			DebugUtil.info(ex);
		}
		return -1l;
	}
	public void initLandMessage(long id,String enter,String leave) throws SQLException{
		final String sql = "insert into `land_message` values (?,?,?);";
		this.getDataBase().excute(sql, id,enter,leave);
	}
	public void initPlayer(UUID uuid,int amount) throws SQLException{
		final String sql = "insert into `land_amount` values (?,?);";
		this.getDataBase().excute(sql, uuid.toString(), amount);
	}
	public void deleteLand(long id) throws SQLException{
		final String landdata_sql = "delete from `land_data` where `id` = ?;";
		this.getDataBase().update(landdata_sql, id);
		final String landmessage_sql = "delete from `land_message` where `id` = ?;";
		this.getDataBase().update(landmessage_sql, id);
	}
	public void updateLand(long id,EDataBaseFormEnum label,Object obj) {
		final StringBuilder strb = new StringBuilder("update `");
		strb.append(label.getFormName()).append("` set `");
		strb.append(label.getLabelName()).append("` ");
		strb.append(" = ? where `id` = ?;");
//		final String sql = "update ? set ? = ? where `id` = ?;";
		this.getDataBase().update(strb.toString(), obj, id);
	}
	public void updatePlayer(UUID uuid,int amount) {
		final String sql = "update `land_amount` set `amount` = ? where `player` = ?;";
		this.getDataBase().update(sql, amount,uuid.toString());
	}
	public ResultSet getLands(int offset, int limit) throws SQLException{
		final StringBuilder builder = new StringBuilder("select * from `land_data`");
		if(offset > 0) builder.append(" offset ").append(offset);
		if(limit > 0) builder.append(" limit ").append(limit);
		builder.append(";");
		return this.getDataBase().getConnection().createStatement().executeQuery(builder.toString());
	}
	public ResultSet getLandMessage(long id) throws SQLException {
		final String sql = "select * from `land_message` where `id` = ? limit 1;";
		return this.getDataBase().query(sql, id);
	}
	public ResultSet getLandsMessage(int offset, int limit) throws SQLException {
		final StringBuilder builder = new StringBuilder("select * from `land_message`");
		if(offset > 0) builder.append(" offset ").append(offset);
		if(limit > 0) builder.append(" limit ").append(limit);
		builder.append(";");
		return this.getDataBase().getConnection().createStatement().executeQuery(builder.toString());
	}
	public ResultSet getPlayers(int offset, int limit) throws SQLException {
		final StringBuilder builder = new StringBuilder("select * from `land_amount`");
		if(offset > 0) builder.append(" offset ").append(offset);
		if(limit > 0) builder.append(" limit ").append(limit);
		builder.append(";");
		return this.getDataBase().getConnection().createStatement().executeQuery(builder.toString());
	}
	public ResultSet getPlayer(UUID player_uuid) throws SQLException {
		final String sql = "select `amount` from `land_amount` where `player` = ? limit 1;";
		return this.getDataBase().query(sql, player_uuid.toString());
	}
	void close() {
		this.getDataBase().close();
	}
	
	public static String jsonFromFlagsParameter(HashMap<String,HashSet<String>> parameter) {
		return gson.toJson(parameter, gson_parameter_type);
	}
	public static HashMap<String,HashSet<String>> jsonToFlagsParameter(String json) {
		return gson.fromJson(json, gson_parameter_type);
	}
	public static String jsonFromFlags(HashSet<String> flags) {
		return gson.toJson(flags, gson_flags_type);
	}
	public static HashSet<String> jsonToFlags(String json) {
		return gson.fromJson(json, gson_flags_type);
	}
}